#pragma once
#include <iostream>

class VectorXYZ {

public:
	/* Constructor / Deconstructor */
	VectorXYZ(float XCoord =0, float YCoord =0, float ZCoord =0);
	
	/* Set Routines */
	void set(float XCoord =0, float YCoord =0, float ZCoord =0);
	void set(VectorXYZ v);

	/* Other Functions */
	void Normalize();
	float Magnitude();

	VectorXYZ Proj (VectorXYZ target); // projection
	VectorXYZ Perp (VectorXYZ target); // perpendicular component

	/* Linear Transformations */
	void scale (float scaleFactor);
	void rotate (float angle, VectorXYZ axis);
	void rotate (VectorXYZ basis, VectorXYZ newbasis);
	void translate (VectorXYZ translateV);

	/* Vector Operations */
	friend VectorXYZ operator+ (VectorXYZ &v1, VectorXYZ &v2);
	friend VectorXYZ operator- (VectorXYZ &v1, VectorXYZ &v2);
	friend float	 operator* (VectorXYZ &v1, VectorXYZ &v2); // Dot Product
	friend VectorXYZ operator% (VectorXYZ &v1, VectorXYZ &v2); // Cross Product

	friend void operator+= (VectorXYZ &v1, VectorXYZ &v2);
	friend void operator-= (VectorXYZ &v1, VectorXYZ &v2);
	friend void operator%= (VectorXYZ &v1, VectorXYZ &v2); // Cross Product

	friend VectorXYZ operator- (VectorXYZ &v1);

	/* Scalar Operations */
	friend VectorXYZ operator* (VectorXYZ v1, float num);
	friend VectorXYZ operator/ (VectorXYZ v1, float num);

	friend VectorXYZ operator* (float num, VectorXYZ v1);
	
	friend void operator*= (VectorXYZ &v1, float num);
	friend void operator/= (VectorXYZ &v1, float num);
	
	/* Output Stream */
	friend std::ostream& operator<< (std::ostream &output, VectorXYZ &v);

	/* Data Members */
	float x, y, z;

private:
	// Actual rotation function, called by the two rotate()s
	void RodriguesRotate(float sine, float cosine, VectorXYZ axis);
};

/* ******************************************* */

